<script setup>

import {getCurrentInstance, onMounted, reactive, ref, toRaw, watch, defineExpose} from "vue";
import api from "@/request/apis.js";
import {nanoid} from "nanoid";
import {Checkbox, Input, Option, Select, Tag} from "view-ui-plus";
import JsonEditor from 'jsoneditor';
import 'jsoneditor/dist/jsoneditor.min.css';

const {proxy} = getCurrentInstance();

const props = defineProps(["params", "isViewBasicFieldFlag", "isViewArrayFlag", "isAddColumnFlag",
  "isUpdateColumnFlag", "isRemoveColumnFlag", "isAddChildrenColumnFlag",
  "isMappingColumnFlag", "mappingValueFunc", "rowSelect"]);

//
// const props.params = ref({
//   isArrayFlag: false,
//   basicFieldType: null,
//   basicTypeFlag: false,
//   params: []
// });
// alert(JSON.stringify(props))
const c = [
  {
    title: 'fieldCode',
    key: '编码',
    width: 200,
    slot: 'fieldCode',
    tree: true
  },
  {
    title: 'fieldName',
    key: 'fieldName',
    width: 200,
    slot: 'fieldName'
  },
  {
    title: 'fieldType',
    key: 'fieldType',
    width: 200,
    slot: 'fieldType'
  },
  {
    title: 'fieldDesc',
    key: 'fieldDesc',
    width: 200,
    slot: 'fieldDesc'
  },
  {
    title: 'isArrayFlag',
    key: 'isArrayFlag',
    width: 200,
    slot: 'isArrayFlag'
  }
];

if (props.isMappingColumnFlag) {
  c.push({
    title: 'mappingValue',
    key: 'mappingValue',
    width: 200,
    slot: 'mappingValue'
  })
}

c.push({
  title: 'action',
  slot: 'action',
  width: 200,
  fixed: 'right',
  align: 'center'
})
const paramColumns = ref(c);

const addEmptyHeaders = () => {
  if (!props.params.params) {
    props.params.params = [];
  }
  repeatSetEditFlag(props.params.params);
  addRow(props.params.params);
}
const addRow = (row) => {

  const id = nanoid(5);
  const d = {
    _key: id,
    fieldCode: null,
    fieldName: null,
    fieldType: null,
    fieldDesc: null,
    children: [],
    editorFlag: false,
    _showChildren: true,
    isArrayFlag: false
  };
  row.push(d);
}

const repeatSetEditFlag = (list) => {
  if (!list) {
    return null;
  }
  let b = null;
  list.forEach(item => {
    item.editorFlag = false;
    if (item.children && item.children.length) {
      b = repeatSetEditFlag(item.children);
    }

  });
  return b;
}

const getFieldName = (row) => {
  if (!row.fieldType) {
    return
  }
  let result = "";
  for (const fieldType of fieldTypeList.value) {
    if (fieldType.code == row.fieldType) {
      result = fieldType.name;
    }
  }
  return result;
}
const remove = (row, index) => {
  const data = repeatListDoit(props.params.params, row);
  if (!data) {
    return
  }
  data.splice(index, 1);

}

const valueChange = (row, key) => {
  const rowb = repeatDoit(props.params.params, row);
  if (!rowb) {
    return
  }
  rowb[key] = row[key];
}

const repeatDoit = (list, row) => {
  if (!list) {
    return null;
  }
  let b = null;
  list.forEach(item => {
    if (item._key === row._key) {
      b = item;
    } else {
      if (item.children && item.children.length) {
        b = repeatDoit(item.children, row);
      }
    }
  });
  return b;
}

const repeatCompPath = (list, row, path) => {
  if (!list) {
    return null;
  }
  let b = null;
  list.forEach(item => {
    item.path = path + "." + item.fieldCode;
    if (item._key === row._key) {
      b = item;
    } else {
      if (item.children && item.children.length) {
        b = repeatCompPath(item.children, row, item.path);
      }
    }
  });
  return b;
}


const repeatListDoit = (list, row) => {
  if (!list) {
    return null;
  }
  let b = null;
  list.forEach(item => {
    if (item._key === row._key) {
      b = list;
    } else {
      if (item.children && item.children.length) {
        b = repeatListDoit(item.children, row);
      }
    }
  });
  return b;
}

const fieldTypeList = ref([]);
const queryFieldTypeList = async () => {
  fieldTypeList.value = await api.queryFieldTypeList();
}

// const editorFlag = ref(false);
const editor = (row) => {
  const data = repeatDoit(props.params.params, row);
  if (!data) {
    return
  }
  data.editorFlag = true;
  row.editorFlag = true;
}


onMounted(async () => {
  await queryFieldTypeList();
})

const addChildren = (row) => {

  const data = repeatDoit(props.params.params, row);
  data.editorFlag = false;
  if (!data.children) {
    data.children = [];
  }
  if (row.fieldType != 'Object') {
    proxy.$message.error("不是Object类型不能新增子集")
    return
  }
  addRow(data.children);
}

const viewType = ref(true);

const viewTypeChange = (c, n) => {
  viewType.value = !viewType.value;
  if (!viewType.value) {
    setTimeout(() => {
      initJsonEditor();
    }, 0)
  } else {
    if (!je.value) {
      return
    }
    const value = je.value.getText();
    props.params.params = JSON.parse(value);
  }
}

const jsonEditor = ref();

const je = ref();

const initJsonEditor = () => {

  const options = {
    "modes": ["code", "tree", "form", "text", "preview"],
    "mode": "code"
  }
  je.value = new JsonEditor(jsonEditor.value, options);
  // const initJson = {};
  // editor.value.set(initJson);
  je.value.set(props.params.params || {});
}

const selectRow = ref();

const rowClick = (row, index) => {
  selectRow.value = row;
  // clickRow.value = row;

  //这里需要补全path
  const rootPath = "$";
  const rowb = repeatCompPath(props.params.params, row, rootPath);
  clickRow.value = rowb;
  clearHiLight(props.params.params);
  //这里需要回调
  if (props.rowSelect) {
    props.rowSelect(clickRow.value);
  }

}

const getSelectRow = () => {
  return clickRow.value;
}


const findRowByPath = (list, path) => {
  if (!list) {
    return null;
  }
  let b = null;
  list.forEach(item => {
    if (item.path === path) {
      b = item;
    } else {
      if (item.children && item.children.length) {
        b = findRowByPath(item.children, path);
      }
    }
  });
  return b;
}

const clearHiLight = (list) => {
  if (!list) {
    return null;
  }
  let b = null;
  list.forEach(item => {
    item.hiLightFlag = false;
    if (item.children && item.children.length) {
      b = clearHiLight(item.children);
    }
  });
  return b;
}

const repairJson = (newValue) => {
  if (!newValue.params) {
    newValue.params = [];
  }
  if (!(newValue.params instanceof Array)) {
    newValue.params = [newValue.params];
  }

  newValue.basicTypeFlag = strBoolToBool(newValue.basicTypeFlag);
  newValue.isArrayFlag = strBoolToBool(newValue.isArrayFlag);


  for (const f of newValue.params) {
    f.editorFlag = strBoolToBool(f.editorFlag);
    f.hiLightFlag = strBoolToBool(f.hiLightFlag);
    f.isArrayFlag = strBoolToBool(f.isArrayFlag);
    f._showChildren = strBoolToBool(f._showChildren);
  }
  return newValue;
}

const strBoolToBool = (boolStr) => {
  if (boolStr && boolStr == 'false') {
    boolStr = false;
  }
  if (boolStr && boolStr == 'true') {
    boolStr = true;
  }
  return boolStr;
}
const mappingRowHiLight = (mappingValue) => {
  clearHiLight(props.params.params);
  if (!mappingValue) {
    return;
  }

  const rootPath = "$";
  repeatCompPath(props.params.params, {}, rootPath);

  //从row中找到这个然后添加背景颜色
  const row = findRowByPath(props.params.params, mappingValue);
  if (!row) {
    return
  }
  row.hiLightFlag = true;

}
defineExpose({
  getSelectRow, mappingRowHiLight, repairJson
});

const clickRow = ref();
const mappingValueNow = (row, index) => {
  if (props.mappingValueFunc) {
    props.mappingValueFunc(clickRow.value);
  }
}

const unMappingValueNow = (row, index) => {
  row.mappingValue = "";
}

const uploadInput = ref();
const importParamDefine = () => {
  const file = uploadInput.value.files[0];
  if (file) {

    const reader = new FileReader();

    reader.onload = (e) => {
      const data = e.target.result;
      if (data) {
        paramsCopy(data);
      }
    }
    reader.readAsText(file)
  }
}
const paramsCopy = (data) => {

  let d = null;

  try {
    d = JSON.parse(data);
  } catch (e) {

  }
  if (!d) {
    proxy.$message.error("错误的json数据");
    return
  }

  //特征 很明显
  if (d.params && d.basicTypeFlag != null && d.isArrayFlag != null) {
    props.params.params = d.params;
    props.params.basicTypeFlag = d.basicTypeFlag;
    props.params.isArrayFlag = d.isArrayFlag;
  } else {
    //原始json导入

    if (d instanceof Array) {
      props.params.isArrayFlag = true;
      d = d[0];//从数组中获取一个元素
    }
    let p = jsonToParamDefine(d);
    if (!p) {
      p = [];
    }
    props.params.params = p;
  }
  proxy.$message.success("导入成功");
}

const jsonToParamDefine = (d) => {
  const de = [];
  //把元素展开
  for (const c in d) {
    let cb = d[c];
    const id = nanoid(5);
    const tpdata = {
      _key: id,
      fieldCode: c,
      fieldName: c,
      fieldType: "String",
      fieldDesc: c,
      children: [],
      editorFlag: false,
      _showChildren: true,
      isArrayFlag: false
    };
    if (cb instanceof Array) {
      tpdata.isArrayFlag = true;
      cb = cb[0];
    }

    if (isObject(cb)) {
      tpdata.fieldType = "Object";
      tpdata.children = jsonToParamDefine(cb);
    }
    de.push(tpdata);
  }
  return de;

}
const isObject = (value) => {
  return value instanceof Object;
}
const exportJsonToFile = () => {
  //把json导出一把
  downloadFile(JSON.stringify(props.params, null, 2), "params.json", "text/plain");
}

const exportJsonToText = () => {
  copyToClip(JSON.stringify(props.params, null, 2));
  proxy.$message.info("导出到粘贴板成功");
  return true;
}

const ztbImportJson = async () => {
  const d = await getClipboardContent();

  if (d) {
    paramsCopy(d);
  }
}

const getClipboardContent = async () => {
  try {
    const text = await navigator.clipboard.readText(); // 获取粘贴板的文本内容
    return text;
  } catch (error) {
    console.error('无法读取粘贴板内容', error);
  }
}

/**
 * 复制多行内容到粘贴板
 * contentArray: 需要复制的内容（传一个字符串数组）
 * message : 复制完后的提示，不传则默认提示"复制成功"
 */
const copyToClip = (contentArray) => {

  const textarea = document.createElement('textarea');
  textarea.value = contentArray;
  document.body.appendChild(textarea);
  textarea.select();
  if (document.execCommand('copy')) {
    document.execCommand('copy');
  }
  document.body.removeChild(textarea);
}

const downloadFile = (data, filename, type) => {
  // 创建 Blob 对象
  const blob = new Blob([data], {type: type});

  // 判断当前浏览器是否是IE，由于IE是没有download 方法的，需要用msSaveBlob() 或 msSaveOrOpenBlob()
  if (window.navigator && window.navigator.msSaveOrOpenBlob) {
    // 兼容IE
    window.navigator.msSaveOrOpenBlob(blob, filename)
  } else {
    // 创建 URL 对象
    const url = URL.createObjectURL(blob);

    // 创建链接
    const link = document.createElement('a');
    link.href = url;
    link.download = filename;

    // 模拟点击链接进行下载
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);

    // 释放 URL 对象
    URL.revokeObjectURL(url);
  }
}
</script>

<template>
  <el-row justify="start" style="margin-top: 10px">
    <el-col :span="10">

      <el-popover
          placement="top-start"
          title="导入"
          :width="200"
          trigger="click"
      >
        <template #reference>
          <el-button type="primary">
            导入
          </el-button>
        </template>

        <el-row>
          <el-col :span="24">
            <el-button @click="uploadInput.click();">json导入</el-button>
            <input type="file" ref="uploadInput" @change="importParamDefine" style="display: none"/>
          </el-col>
          &nbsp; &nbsp; &nbsp;
          <el-col :span="24">
            <el-button @click="ztbImportJson">粘贴板导入</el-button>
          </el-col>
        </el-row>

      </el-popover>

      <el-popover
          placement="top-start"
          title="导出"
          :width="200"
          trigger="click"
      >
        <template #reference>
          <el-button type="primary">
            导出
          </el-button>
        </template>

        <el-row>
          <el-col :span="24">
            <el-button @click="exportJsonToFile">导出到文件</el-button>
          </el-col>
          &nbsp; &nbsp; &nbsp;
          <el-col :span="24">
            <el-button @click="exportJsonToText">导出到文本</el-button>
          </el-col>
        </el-row>

      </el-popover>
    </el-col>
    <el-col :span="4">
      <el-checkbox v-model="props.params.isArrayFlag" v-show="props.isViewArrayFlag" label="是否数组"
                   size="large"/>
    </el-col>
    <el-col :span="4">
      <el-checkbox v-show="props.isViewBasicFieldFlag" v-model="props.params.basicTypeFlag" label="基本数据类型"
                   size="large"/>
    </el-col>
    <el-col :span="2">
      <el-button v-show="!props.params.basicTypeFlag && (props.isAddColumnFlag==null||props.isAddColumnFlag)"
                 type="primary" @click="addEmptyHeaders">新增
      </el-button>
    </el-col>
    <el-col :span="2">
      <Tag v-show="!props.params.basicTypeFlag" checkable :checked="viewType" @click="viewTypeChange"
           color="primary">table
      </Tag>
    </el-col>
    <el-col :span="2">
      <Tag v-show="!props.params.basicTypeFlag" checkable :checked="!viewType" @click="viewTypeChange"
           color="success">json
      </Tag>
    </el-col>
  </el-row>
  <el-row justify="start" style="margin-top: 10px" v-show="props.params.basicTypeFlag">
    <el-col :span="24">
      <el-select v-model="props.params.basicFieldType"
                 clearable filterable>
        <el-option v-for="item in fieldTypeList" :label="item.name" :value="item.code"
                   :key="item.code"></el-option>
      </el-select>
    </el-col>
  </el-row>
  <el-row justify="start" style="margin-top: 10px" v-show="!props.params.basicTypeFlag">
    <el-col :span="24">
      <div v-if="viewType">
        <Table row-key="_key" border :columns="paramColumns"
               height="500"
               @on-row-click="rowClick" stripe highlight-row
               :data="props.params.params">

          <template #fieldCode="{ row }">
            <div :class="row.hiLightFlag?'hilight':''">
              <Input v-show="row.editorFlag" v-model="row.fieldCode"
                     :on-change="valueChange(row,'fieldCode')"
                     placeholder="请输入fieldCode"></Input>

              <Tag v-show="!row.editorFlag">{{ row.fieldCode }}</Tag>
            </div>
          </template>


          <template #fieldName="{ row }">
            <Input v-show="row.editorFlag" v-model="row.fieldName"
                   :on-change="valueChange(row,'fieldName')"
                   placeholder="请输入fieldName"></Input>

            <Tag v-show="!row.editorFlag">{{ row.fieldName }}</Tag>
          </template>

          <template #fieldType="{ row }">
            <el-select v-show="row.editorFlag" v-model="row.fieldType"
                       :on-change="valueChange(row,'fieldType')"
                       clearable filterable>
              <el-option v-for="item in fieldTypeList" :label="item.name" :value="item.code"
                         :key="item.code"></el-option>
            </el-select>

            <Tag v-show="!row.editorFlag">{{ getFieldName(row) }}</Tag>
          </template>

          <template #fieldDesc="{ row }">
            <Input v-show="row.editorFlag" v-model="row.fieldDesc"
                   :on-change="valueChange(row,'fieldDesc')"
                   placeholder="请输入fieldDesc"></Input>

            <Tag v-show="!row.editorFlag">{{ row.fieldDesc }}</Tag>
          </template>

          <template #isArrayFlag="{ row }">
            <Checkbox v-show="row.editorFlag" v-model="row.isArrayFlag"
                      :on-change="valueChange(row,'isArrayFlag')"/>
            <Tag v-show="!row.editorFlag">{{ row.isArrayFlag ? '是' : '否' }}</Tag>
          </template>

          <template v-if="props.isMappingColumnFlag" #mappingValue="{ row }">

            <Input v-show="row.editorFlag" v-model="row.mappingValue"
                   :on-change="valueChange(row,'mappingValue')"
                   placeholder="请输入mappingValue"></Input>

            <Tag v-show="!row.editorFlag">{{ row.mappingValue }}</Tag>
          </template>

          <template #action="{ row, index }">
            <el-space wrap v-show="!row.editorFlag">
              <Button v-show="(props.isUpdateColumnFlag==null||props.isUpdateColumnFlag)" type="primary" size="small"
                      @click="editor(row)">编辑
              </Button>
              <Button v-show="(props.isAddChildrenColumnFlag==null||props.isAddChildrenColumnFlag)" type="primary"
                      size="small" @click="addChildren(row)">子集
              </Button>
              <Button v-show="(props.isRemoveColumnFlag==null||props.isRemoveColumnFlag)" type="error" size="small"
                      @click="remove(row,index)">删除
              </Button>

              <Button v-show="(props.isMappingColumnFlag&&!row.mappingValue)" type="error" size="small"
                      @click="mappingValueNow(row,index)">映射
              </Button>

              <Button v-show="(props.isMappingColumnFlag&&row.mappingValue)" type="error" size="small"
                      @click="unMappingValueNow(row,index)">取消映射
              </Button>

            </el-space>

            <el-space wrap v-show="row.editorFlag">
              <Button type="primary" size="small" @click="repeatSetEditFlag(props.params.params)">确定</Button>
            </el-space>
          </template>
        </Table>
      </div>

      <div v-if="!viewType">

        <div class="jsoneditor" ref="jsonEditor" style="width: 100%; height: 600px;"></div>

      </div>
    </el-col>
  </el-row>
</template>

<style scoped>

.hilight {
  border: 5px solid transparent;
  border-top: 1px solid #46cc46;
  border-radius: 25%;
}


</style>